/*
 * @Author: 260156 260156@gree.com.cn
 * @Date: 2022-07-26 08:55:12
 * @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @LastEditTime: 2023-09-13 14:29:16
 * @FilePath: \gree-zst-web\src\utils\request\index.ts
 * @Description:
 *
 * Copyright (c) 2022 by 260156 260156@gree.com.cn, All Rights Reserved.
 */
import axios from "axios";
// import type {axios} from 'axios'
import { ElMessage, ElMessageBox } from "element-plus";
import type { BasicFetchResult } from "#/request";
import { requireLoginMessageBox } from "../helper";
import type { AxiosRequestConfig } from "axios";
import { RequestMethods } from "./RequestMehods";
import { ElLoading } from "element-plus";
import _ from 'lodash'

const { VITE_BASE } = import.meta.env;

const axiosInstance = axios.create({
  baseURL: VITE_BASE,
});

let loading: any;
let requestNum = 0;
let loadingNum = 0

function showLoading(target:any) {
  // 由于加了抖动，可能出现 loadingNum 为0但还需等 300ms 才能清空 loading 的尴尬时间段，如果此时创建 loading 会覆盖旧的，所以必须等上一个 loading 结束才能添加新的 loading
  if(loadingNum === 0 && !loading) {
    loading = ElLoading.service({
      background: 'rgba(0,0,0,0.6)',
      lock: true,
      text: '正在加载',
      target: target || 'body'
    })
  }
  loadingNum ++
}
function hideLoading() {
  loadingNum --
  loadingNum = Math.max(loadingNum, 0)
  if(loadingNum === 0) {
    toHideLoading()
  }
}

// 防抖：防止连续请求时loading出现闪烁的问题
let toHideLoading = _.debounce(() =>{
  loading.close();
  loading = null;
}, 300)

axiosInstance.interceptors.request.use((config: any) => {
  if(config.headers.showLoading) {
    showLoading(config.headers.loadingTarget);
  }
  requestNum++;
  return config
}, err => {
  requestNum --;
  requestNum = Math.max(requestNum, 0);
  if(err.headers.showLoading) {
    hideLoading();
  }
  ElMessage.error('请求超时！');
  return Promise.resolve(err)
})

axiosInstance.interceptors.response.use(
  async (response) => {
    requestNum --;
    requestNum = Math.max(requestNum, 0);
    if(loading) { // response.config.headers.showLoading
      hideLoading();
    }
    const { data: responseData, status: responseStatus, statusText } = response;
    const { desc, status, success, data } = responseData || {};

    if (responseStatus === 200) {
      if (success) {
        return response;
      } else if (status === 401) {
        // localStorage.removeItem('callback') // 清空sessionStorage中的菜单、按钮权限信息
        // sessionStorage.removeItem('state') // 清空sessionStorage中的菜单、按钮权限信息
        localStorage.clear();
        sessionStorage.clear();
        if (requestNum === 0) {
          await requireLoginMessageBox({ message: desc });
        }
        return Promise.reject(desc || statusText);
      }
    }
    let errorMessage: string = data;
    if (data && typeof data === "object") {
      errorMessage = JSON.stringify(data);
    }
    if (errorMessage) {
      ElMessageBox.alert(errorMessage, "失败", {
        confirmButtonText: "确定",
        type: "error",
      });
      return Promise.reject(errorMessage);
    } else {
      ElMessage.error(desc || statusText);
      return Promise.reject(desc || statusText);
    }
  },
  (error) => {
    let title = "其他错误";
    requestNum --;
    requestNum = Math.max(requestNum, 0);
    if(loading) { // error.config.headers.showLoading
      hideLoading();
    }
    if (error.response) {
      const { status, statusText: message } = error.response;
      if (status >= 400 && status < 500) {
        title = `${status}: 请求错误`;
      } else if (status >= 500) {
        title = `${status}: 服务器错误`;
      }
      ElMessage.error(title + " - " + message);
      return Promise.reject(error.response);
    } else if (error.message) {
      ElMessage.error(error.message);
      return Promise.reject(error.message);
    } else {
      return Promise.reject(new Error("请求中断"));
    }
  }
);

const axiosRequest = async <T = any>(
  config: AxiosRequestConfig
): Promise<T> => {
  try {
    const {
      data: { data },
    } = await axiosInstance.request<BasicFetchResult<T>>(config);
    return Promise.resolve(data);
  } catch (err) {
    return Promise.reject(err);
  }
};

// 添加request/get/post/put/delete...
const myAxios = new RequestMethods(axiosRequest);

// myAxios.get({url: "/loginCallback"})


/**
 * @description: 数据请求
 * 使用方法：
 * myAxios.request(config)  —— 参数与方法axiosRequest一致
 * myAxios.get(config)
 * myAxios.post(config)
 * myAxios.delete(config)
 * myAxios.put(config)
 */
export default myAxios;
